﻿using AgencyManagerSystem.Common;
using AgencyManagerSystem.DataFetcher;
using Dapper.Contrib.Extensions;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;

namespace AgencyManagerSystem.DataUpdater
{
    public abstract class BaseUpdater<T> where T : DBModel
    {
        public virtual event DataUpdatingHandler<T> DataUpdating;
        public virtual event DataDeletingHandler<T> DataDeleting;
        public virtual event DataApprovingHandler<T> DataApproving;

        internal string TableName { get; private set; }
        private FullUserProfile fullUserProfile;
        protected FullUserProfile CurrentUser
        {
            private set { fullUserProfile = value; }
            get
            {
                if (fullUserProfile == null)
                {
                    fullUserProfile = MyHttpContext.Current.Items[Definer.CURRENT_PROFILE] as FullUserProfile;
                }
                return fullUserProfile;
            }
        }
        protected BaseFetcher<T> baseFetcher;
        internal BaseUpdater(BaseFetcher<T> fetcher)
        {
            TableAttribute tableNameAttribute = typeof(T).GetCustomAttribute<TableAttribute>();
            if (tableNameAttribute != null)
            {
                TableName = tableNameAttribute.Name;
            }
            this.baseFetcher = fetcher;
        }
        public virtual int Save(T data,out string message)
        {
            message = "保存成功";//保存失败会被重新设置
            long result = 0;
            T db = baseFetcher.Get(data.AutoId);
            IDbTransaction dbTransaction = DBHelper.GetTran();
            DataUpdatingEventArgs<T> dataUpdatingEventArgs = new DataUpdatingEventArgs<T>() { Insert = data, Delete = db };
            if (DataUpdating != null)
            {
                LogHelper.Log(this.GetType().Name,"SAVE:正在检查数据合法性");
                foreach (DataUpdatingHandler<T> handler in DataUpdating.GetInvocationList())
                {
                    handler(this, dataUpdatingEventArgs);
                    if((dataUpdatingEventArgs.Cancel))
                    {
                        message = dataUpdatingEventArgs.Message;
                        LogHelper.Warn(this.GetType().Name, "SAVE:检查数据合法性不通过："+message);
                        DBHelper.Commit(false);
                        return 0;
                    }
                }
            }
            data.Flag += 1;
            if (db==null)
            {
                LogHelper.Log(this.GetType().Name, String.Format("SAVE:从数据库中创建{0}对象",TableName));
                data.Creator = CurrentUser.UserId;
                data.CreateTime = Util.Now();
                data.CreateDepartment = CurrentUser.Department;
                try
                {
                    result = dbTransaction.Insert(data);
                    data.AutoId = (int)result;
                }
                catch(Exception ex)
                {
                    message = ex.Message;
                    LogHelper.Err(this.GetType().Name,ex.Message+ex.StackTrace);
                }
            }
            else
            {
                LogHelper.Log(this.GetType().Name, String.Format("SAVE:修改数据库中的{0}对象", TableName));
                data.Modifier = CurrentUser.UserId;
                data.ModifyTime = Util.Now();
                data.ModifyDepartment = CurrentUser.Department;
                bool successed = false;
                try
                {
                    successed = dbTransaction.Update(data);
                }
                catch (Exception ex)
                {
                    message = ex.Message;
                    LogHelper.Err(this.GetType().Name, ex.Message + ex.StackTrace);
                }
                if (successed)
                    result = data.AutoId;
            }
            if (result == 0)
            {
                DBHelper.Commit(false);
                data.Flag -= 1;
                LogHelper.Err(this.GetType().Name, String.Format("SAVE:保存数据库中的{0}对象{1}失败", TableName, data.AutoId));
            }
            else
            {
                LogHelper.Log(this.GetType().Name, String.Format("SAVE:保存数据库中的{0}对象{1}成功", TableName,result));
            }
            return (int)result;
        }
        
        public virtual bool Delete(T data, out string message)
        {
            if(data==null)
            {
                message = "系统内部错误";
                return false;
            }
            return Delete(data.AutoId,out message);
        }
        public virtual bool Delete(int id, out string message)
        {
            message = "删除成功";//保存失败会被重新设置
            IDbTransaction dbTransaction = DBHelper.GetTran();
            T db = baseFetcher.Get(id);
            DataDeletingEventArgs<T> dataDeletingEventArgs = new DataDeletingEventArgs<T>() { Delete = db };
            if (db == null)
            {
                message = "系统不存在该记录";
                return false;
            }
            if (DataUpdating != null)
            {
                LogHelper.Log(this.GetType().Name, "DELETE:正在检查数据合法性");

                foreach (DataDeletingHandler<T> handler in DataDeleting.GetInvocationList())
                {
                    handler(this, dataDeletingEventArgs);
                    if ((dataDeletingEventArgs.Cancel))
                    {
                        message = dataDeletingEventArgs.Message;
                        LogHelper.Warn(this.GetType().Name, "DELETE:检查数据合法性不通过：" + message);
                        DBHelper.Commit(false);
                        return false;
                    }
                }
            }
            bool result = false;
            try
            {
                result = dbTransaction.Delete(db);
                LogHelper.Log(this.GetType().Name, String.Format("DELETE:删除数据库中的{0}对象{1}成功", TableName, id));

            }
            catch (Exception ex)
            {
                LogHelper.Err(this.GetType().Name, String.Format("DELETE:删除数据库中的{0}对象{1}失败", TableName, id));
                message = ex.Message;
            }
            return result;
        }
        public virtual bool Approve(int dataId, ApproveCode status ,out string message)
        {
            message = "审核成功";
            T db = baseFetcher.Get(dataId);
            if (db == null)
            {
                LogHelper.Err(this.GetType().Name,String.Format("APPROVE:{0}[{1}]已经被删除",TableName,dataId));
                message = "数据已经被删除或不存在";
                return false;
            }
            IDbTransaction dbTransaction = DBHelper.GetTran();
            DataApprovingEventArgs<T> dataApprovingEventArgs = new DataApprovingEventArgs<T>() { DataInDB = db, Status = status };
            if (DataApproving != null)
            {
                LogHelper.Log(this.GetType().Name, "APPROVE:正在检查数据合法性");

                foreach (DataApprovingHandler<T> handler in DataUpdating.GetInvocationList())
                {
                    handler(this, dataApprovingEventArgs);
                    if ((dataApprovingEventArgs.Cancel))
                    {
                        message = dataApprovingEventArgs.Message;
                        LogHelper.Warn(this.GetType().Name, "APPROVE:检查数据合法性不通过：" + message);
                        DBHelper.Commit(false);
                        return false;
                    }
                }
            }
            db.Flag += 1;
            db.ApproveDepartment = CurrentUser.Department;
            db.Approver = CurrentUser.UserId;
            db.ApproveTime = Util.Now();
            db.ApproveFlag = (int)status;
            bool successed = false;
            try
            {
                successed = dbTransaction.Update(db);
                LogHelper.Log(this.GetType().Name, String.Format("APPROVE:审核{0}对象{1}成功", TableName, dataId));
            }
            catch (Exception ex)
            {
                message = ex.Message;
                LogHelper.Err(this.GetType().Name, ex.Message + ex.StackTrace);
            }
            if (!successed)
            {
                db.Flag -= 1;
                DBHelper.Commit(false);
            }
            return successed;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="listInDb"></param>
        /// <returns>数组第一元素是insert，第二是modify，第三是delete</returns>
        public IEnumerable<TS>[] ListSplit<TS>(IEnumerable<TS> list, IEnumerable<TS> listInDb) where TS : DBModel
        {
            var oldIdList = from item in listInDb select item.AutoId;
            var newIdList = from item in list where item.AutoId != 0 select item.AutoId;
            var detailInsert = from item in list where item.AutoId == 0 select item;
            var detailModify = from item in list where oldIdList.Contains(item.AutoId) select item;
            var detailDelete = from item in listInDb where !newIdList.Contains(item.AutoId) select item;
            return new IEnumerable<TS>[] { detailInsert, detailModify, detailDelete };
        }
    }
}
